package com.winchain.chainbill.bill.biz.receive.service.impl;

import com.shell.bee.base.exception.UnCheckException;
import com.shell.bee.base.exception.UnCheckMsgException;
import com.shell.bee.base.utils.DateUtil;
import com.shell.bee.persistence.transaction.Transaction;
import com.shell.bee.persistence.transaction.TransactionUtil;
import com.winchain.chainbill.ChainBillUtil;
import com.winchain.chainbill.asset.biz.credit.rx.BillAssetTranSubscriber;
import com.winchain.chainbill.basic.context.TimeoutOperation;
import com.winchain.chainbill.bill.base.po.CbOpt;
import com.winchain.chainbill.bill.base.po.CbRcv;
import com.winchain.chainbill.bill.base.po.CbRec;
import com.winchain.chainbill.bill.base.service.CbRcvService;
import com.winchain.chainbill.bill.biz.Bill;
import com.winchain.chainbill.bill.biz.BillEvent;
import com.winchain.chainbill.bill.biz.contract.rx.ContractSignSubscriber;
import com.winchain.chainbill.bill.biz.receive.rx.BillPayeeSubscriber;
import com.winchain.chainbill.bill.biz.receive.rx.BillRcvDenySubscriber;
import com.winchain.chainbill.bill.biz.receive.rx.BillRcvFileUploadSubscriber;
import com.winchain.chainbill.bill.biz.receive.rx.BillRcvMsgSubscriber;
import com.winchain.chainbill.bill.biz.receive.rx.BillRcvSubscriber;
import com.winchain.chainbill.bill.biz.receive.rx.BillRcvTranSubscriber;
import com.winchain.chainbill.bill.biz.receive.rx.BillSndDirRcvTranSubscriber;
import com.winchain.chainbill.bill.biz.receive.service.BillRcvService;
import com.winchain.chainbill.bill.biz.receive.vo.BillRcv;
import com.winchain.chainbill.bill.biz.send.rx.BatchBillEvent;
import com.winchain.chainbill.bill.biz.send.rx.BillHldrSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillMoveSubscriber;
import com.winchain.chainbill.bill.biz.send.rx.BillOptSubscriber;
import com.winchain.chainbill.bill.biz.send.vo.BatchBillStats;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import rx.Observable;

@Service("billRcvService")
public class BillRcvServiceImpl implements BillRcvService {
	@Autowired
	private CbRcvService cbRcvService;
	@Autowired
	private BillRcvDenySubscriber billRcvDenySubscriber;
	@Autowired
	private BillOptSubscriber billOptSubscriber;
	@Autowired
	private BillMoveSubscriber billMoveSubscriber;
	@Autowired
	private BillRcvSubscriber billRcvSubscriber;
	@Autowired
	private BillRcvFileUploadSubscriber billRcvFileUploadSubscriber;
	@Autowired
	private BillHldrSubscriber billHldrSubscriber;
	@Autowired
	private BillPayeeSubscriber billPayeeSubscriber;
	@Autowired
	private BillRcvMsgSubscriber billRcvMsgSubscriber;
	@Autowired
	private BillAssetTranSubscriber billAssetTranSubscriber;
	@Autowired
	private BillRcvTranSubscriber billRcvTranSubscriber;
	@Autowired
	private ContractSignSubscriber<CbRcv> contractSignSubscriber;
	@Autowired
	private BillSndDirRcvTranSubscriber billSndDirRcvTranSubscriber;

	public String receive(String billId, String fileIds, String contracts, String invoices, String phoneCode,
			String location) {
		BillRcv billRcv = new BillRcv();
		billRcv.setBillId(billId);
		billRcv.setRcvState("1");
		BillRcv record = this.cbRcvService.selectBillRcv(billRcv);
		if (record == null) {
			throw new UnCheckException("����������������������");
		}
		record.setRcvDate(DateUtil.getSystemDate());

		Bill<CbRcv> bill = new Bill();
		bill.setSource(record.getRcv());
		bill.setRec(record.getRec());
		BillEvent<CbRcv> event = new BillEvent(bill);

		CbOpt opt = new CbOpt();
		opt.setCurState("S003");
		int level = bill.getRec().getHldrLvl().intValue();
		boolean isNotNeedAprv = record.getConfirmerId().equals(record.getBuyerId());
		if (level == 0) {
			if (isNotNeedAprv) {
				opt.setOptCode("E503");
			} else {
				opt.setOptCode("E005");
			}
		} else {
			opt.setOptCode("E505");
		}
		opt.setRemark("��������");

		TimeoutOperation timeoutOpt = new TimeoutOperation();
		timeoutOpt.setOptCode("E004");
		timeoutOpt.setRemark("��������,������������");

		event.setOperation(opt);
		event.setTimeoutOpt(timeoutOpt);
		event.setValue("fileIds", fileIds);
		event.setValue("contracts", contracts);
		event.setValue("invoices", invoices);
		event.setValue("level", Integer.valueOf(level));
		event.setValue("isNotNeedAprv", Boolean.valueOf(isNotNeedAprv));
		event.setValue("phoneCode", phoneCode);
		event.setValue("location", location);
		Observable<BillEvent<CbRcv>> observers = Observable.just(event);
		observers.subscribe(this.billRcvFileUploadSubscriber);
		observers.subscribe(this.billOptSubscriber);
		observers.subscribe(this.billHldrSubscriber);
		observers.subscribe(this.billMoveSubscriber);
		observers.subscribe(this.billRcvSubscriber);
		observers.subscribe(this.billPayeeSubscriber);
		observers.subscribe(this.billRcvMsgSubscriber);

		observers.subscribe(this.contractSignSubscriber);
		if (level > 0) {
			observers.subscribe(this.billRcvTranSubscriber);
			if (ChainBillUtil.onChain()) {
				Object txSnHost = event.getValue("txSnHost");
				if (txSnHost != null) {
					return (String) txSnHost;
				}
			}
		} else if (isNotNeedAprv) {
			observers.subscribe(this.billSndDirRcvTranSubscriber);
			if (ChainBillUtil.onChain()) {
				Object txSnHost = event.getValue("txSnHost");
				if (txSnHost != null) {
					return (String) txSnHost;
				}
			}
			return "-1";
		}
		return "" + level;
	}

	public BatchBillStats<CbRcv> contractAndreceive(String[] billIds, final String fileIds, final String contracts,
			final String invoices) {
		final BatchBillStats<CbRcv> stats = new BatchBillStats();
		final String[] txSnHost = new String[1];
		for (final String billId : billIds) {
			try {
				TransactionUtil.execute(new Transaction() {
					public void doInTransaction() {
						txSnHost[0] = BillRcvServiceImpl.this.receive(billId, fileIds, contracts, invoices, null, null);
						stats.setTxSnHost(txSnHost[0]);
					}
				}, new int[0]);
			} catch (Exception e) {
				e.printStackTrace();
				if (e.getMessage() != null) {
					stats.addAbnormalMsg(e.getMessage());
				}
				stats.setAffectedRows(-1);
			}
		}
		return stats;
	}

	public BatchBillStats<CbRcv> deny(String remark, String... billIds) {
		return expDeny(remark, false, billIds);
	}

	public BatchBillStats<CbRcv> expDeny(String remark, boolean exp, String... billIds) {
		List<BillRcv> records = this.cbRcvService.getBillRcvByStateAndIds("1", billIds);
		if ((records == null) || (records.size() == 0)) {
			throw new UnCheckMsgException("������������������������");
		}
		BatchBillEvent<BillRcv, CbRcv> event = new BatchBillEvent();
		event.setRecs(records);

		CbOpt opt = new CbOpt();
		opt.setCurState("S003");
		opt.setOptCode("E007");
		opt.setRemark(remark);

		BatchBillStats<CbRcv> stats = new BatchBillStats();

		event.setOperation(opt);
		event.setStats(stats);
		event.setValue("bizType", "cb_rcv");
		event.setValue("exp", Boolean.valueOf(exp));

		Observable<BatchBillEvent<BillRcv, CbRcv>> observers = Observable.just(event);
		observers.subscribe(this.billRcvDenySubscriber);
		String txType = ((BillRcv) records.get(0)).getTxType();
		if ("0".equals(txType)) {
			observers.subscribe(this.billAssetTranSubscriber);
			if (ChainBillUtil.onChain()) {
				Object txSnHost = event.getValue("txSnHost");
				if (txSnHost != null) {
					stats.setTxSnHost((String) txSnHost);
				}
			}
		}
		if (billIds.length > records.size()) {
			stats.addAbnormalMsg("��������������������������");
		}
		return stats;
	}
}
